/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: RxBaseDataMessageConverter
 * @Package com.rx.core.bean
 * @Description: json转换BaseData
 * @author: 陈锦韬
 * @date: 2020\7\26 0026
 * @version V1.0
 * @Copyright: 2020 陈锦韬  All rights reserved.
 */
package com.rx.core.covert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rx.core.base.RxBaseConstant;
import com.rx.core.base.RxBaseData;
import com.rx.core.base.RxResponse;
import com.rx.core.base.RxScanner;
import com.rx.core.bean.RxConfigBean;
//import com.rx.core.data.DataServiceChainConfig;
import com.rx.core.data.RxDataScanner;
import com.rx.core.data.UrlAnalyse;
import com.rx.core.dbase.RxBaseDbMust;
import com.rx.core.enm.MODE_TYPE;
import com.rx.core.enm.RESULT_CODE;
import com.rx.core.enm.RX_LOG_MODE;
import com.rx.core.iface.RelationQuery;
import com.rx.core.util.EmptyChecker;
import com.rx.core.util.RxUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: Administrator
 * @Description: json转换BaseData
 * @date: 2020\7\26 0026
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper=false)
public class RxBaseDataMessageConverter extends AbstractHttpMessageConverter<RxBaseData> {

    @Autowired
    RxConfigBean rxConfigBean;
    private boolean isRxData = false;

    private FastJsonConfig fastJsonConfig = new FastJsonConfig();

    /**
     * 是否是POST请求
     * @param method
     * @return
     */
    private boolean isPastMethod(String method) {
        if(HttpMethod.POST.name().equals(method)) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * 获取URI
     * @return
     */
    private String getRequestURI() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == requestAttributes){
            return null;
        }
        HttpServletRequest request = requestAttributes.getRequest();
        /**
         * 只支持Post请求
         */
        if(!isPastMethod(request.getMethod())) {
            return null;
        }
        return request.getRequestURI();
    }

    /**
     * 匹配支持的url头 如/rx-standard-api
     * @param uri
     * @return
     */
    private boolean urlStartsWithConfig(String uri){
        String[] rxStandardUrlStartArray = rxConfigBean.getRxStandardUrlStart().split(";");

        for (String standardUrlStart:rxStandardUrlStartArray){
            if (uri.startsWith(standardUrlStart)){
                return true;
            }
        }
        return false;
    }
    private boolean supportUri(){
        try{
            String uri = getRequestURI();
            if (EmptyChecker.isEmpty(uri) || EmptyChecker.isEmpty(rxConfigBean.getRxStandardUrlStart())){
                return false;
            }
            String[] uris = uri.split("/");
            if(uris.length < 6){
                return false;
            }
            return urlStartsWithConfig(uri);
        }catch (Throwable e){
            log.error(RX_LOG_MODE.URL_ERROR.getFormat(e),e);
        }
        return false;
    }

    /**
     * 是否支持
     * @param clazz
     * @return
     */
    @Override
    protected boolean supports(Class<?> clazz) {
        isRxData = false;

        /**
         * 支持的URI
         */
        if (!supportUri()){
            return false;
        }

        /**
         * 只要是RxBaseData类型都支持
         */
        Class<?> cls = clazz;
        while (EmptyChecker.notEmpty(cls)){
            if(RxBaseData.class.isAssignableFrom(cls)){
                isRxData = true;
                return true;
            }
            cls = cls.getSuperclass();
        }
        if (Object.class.isAssignableFrom(clazz)){
            return true;
        }
        return false;
    }

    @Override
    protected boolean canRead(@Nullable MediaType mediaType){
        if(!isRxData){
            return false;
        }
        if (EmptyChecker.isEmpty(mediaType)){
            return false;
        }
        /**
         * json 请求
         */
        if (mediaType.includes(MediaType.APPLICATION_JSON)) {
            return true;
        }
        return false;
    }
    @Override
    protected boolean canWrite(@Nullable MediaType mediaType) {
        if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {
            if(EmptyChecker.isEmpty(getSupportedMediaTypes())){
                List<MediaType> mediaTypeList = new ArrayList<>();
                mediaTypeList.add(MediaType.APPLICATION_JSON);
                setSupportedMediaTypes(mediaTypeList);
            }
            return true;
        }

        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.isCompatibleWith(mediaType)) {
                return true;
            }
        }
        return false;
    }

    private Class getFormClass(Class<? extends RxBaseData> clazz,UrlAnalyse url){

        String prefix = "";
        if (MODE_TYPE.DOUBLE.getValue().equalsIgnoreCase(url.getType()) ||
                MODE_TYPE.THREE.getValue().equalsIgnoreCase(url.getType())){
            prefix = MODE_TYPE.DOUBLE.getValue() + "-";
        }

        Class<?> cls = RxDataScanner.getClassByName(prefix + url.getForm());
        if (EmptyChecker.isEmpty(cls)){
            cls = clazz;
        }
        return cls;
    }

    private void assignRelation(RxBaseData rxBaseData,UrlAnalyse url){
        if (MODE_TYPE.DOUBLE.getValue().equalsIgnoreCase(url.getType())){
           // 双表操作
            if (rxBaseData instanceof  RelationQuery){
                Object object = ((RelationQuery) rxBaseData).obtainRelation();
                Class doubleClass = RxScanner.getClassByName(url.getService());
                ((RelationQuery) rxBaseData).assignRelation(JSON.parseObject(JSON.toJSONString(object),doubleClass));
            }
        }

        if (MODE_TYPE.THREE.getValue().equalsIgnoreCase(url.getType())){
           // 三表操作
            String table[] = url.getService().split("_");
            RxUtil.CheckUtil.condition(table.length < 2, RESULT_CODE.MESSAGE,"三表操作URL错误");
            if (rxBaseData instanceof  RelationQuery){
                Object object = ((RelationQuery) rxBaseData).obtainRelation();
                Class doubleClass = RxScanner.getClassByName(MODE_TYPE.DOUBLE.getValue() + "-" + table[0]);
                RxBaseData secondData = (RxBaseData)JSON.parseObject(JSON.toJSONString(object),doubleClass);
                ((RelationQuery) rxBaseData).assignRelation(secondData);

                if (secondData instanceof RelationQuery){
                    Object threeObj = ((RelationQuery) secondData).obtainRelation();
                    Class threeClass = RxScanner.getClassByName(table[1]);
                    RxBaseData threeData = (RxBaseData)JSON.parseObject(JSON.toJSONString(threeObj),threeClass);
                    ((RelationQuery) secondData).assignRelation(threeData);
                }
            }
        }
    }

    @Override
    protected RxBaseData readInternal(Class<? extends RxBaseData> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {

        /**
         * 根据URI获取Class。
         */
        UrlAnalyse url = UrlAnalyse.create(getRequestURI());
        // UTF-8编码
        String json = StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8"));

        log.info(RX_LOG_MODE.REVC.getFormat("host:{}"),inputMessage.getHeaders().getHost());
        log.info(RX_LOG_MODE.REVC.getFormat("uri:{}"),url.getUrl());
        log.info(RX_LOG_MODE.REVC.getFormat("json:\n{}"),json);

        Class<?> cls = getFormClass(clazz,url);
        if (EmptyChecker.notEmpty(url.getMethod())){
            if (url.getMethod().toLowerCase().contains("batch")){
                // 批量
                // Json 转 列表
                RxBaseData rxBaseData = new RxBaseData();
                rxBaseData.setUrlAnalyse(url);
                rxBaseData.setDataList((List<RxBaseData>) JSON.parseArray(json,cls));
                return rxBaseData;
            }
        }
        // Json 转 对象
        RxBaseData rxBaseData = (RxBaseData) JSON.parseObject(json,cls);
        rxBaseData.setUrlAnalyse(url);
        assignRelation(rxBaseData,url);
        return rxBaseData;
    }

    @Override
    protected void writeInternal(RxBaseData rxBaseData, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        if (!RxResponse.class.isAssignableFrom(rxBaseData.getClass())){
            return;
        }

        HttpHeaders headers = outputMessage.getHeaders();
        ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        int len = JSON.writeJSONString(outnew,
                fastJsonConfig.getCharset(),
                rxBaseData,
                fastJsonConfig.getSerializeConfig(),
                fastJsonConfig.getSerializeFilters(),
                fastJsonConfig.getDateFormat(),
                JSON.DEFAULT_GENERATE_FEATURE,
                fastJsonConfig.getSerializerFeatures());
        headers.setContentLength(len);
        /**
         * 打印响应数据
         */
        log.info(RX_LOG_MODE.RESP.getFormat("json:\n{}"),outnew.toString());
        OutputStream out = outputMessage.getBody();
        outnew.writeTo(out);
        outnew.close();
    }
}
